/**
 * 
 */
package travibot.meta.dao.jdbctemplate;

import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import travibot.engine.MaterialFactory;
import travibot.meta.UnitType;
import travibot.meta.dao.UnitTypeDAO;
import travibot.model.Material;
import travibot.utility.DescriptionNotFoundException;
import travibot.utility.LocaleSelector;


/**
 * @author tajzivit
 *
 */
public class UnitTypeDAOJdbcTemplate implements UnitTypeDAO {

    private static final String TABLE_TYPE = "UNIT_TYPE";

    private static final String TABLE_NAME = "UNIT_NAME";

    private static final String TABLE_TEXT = "TEXT";
    
    private static final String TABLE_COST = "COST";
    
    private static final String TABLE_UNIT_COSTS = "UNIT_COSTS";

    private JdbcTemplate jdbcTemplate;

    private LocaleSelector localeSelector;
    
    private MaterialFactory materialFactory;

    public void setDataSource(DataSource dataSource) {

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    
    public void setLocaleSelector(LocaleSelector localeSelector) {

        this.localeSelector = localeSelector;
    }
    
    
    
    private static class BuildingTypeRowMapper implements RowMapper {

        private static final String ID = "ID_TYPE";
        private static final String NAME = "text";
        private static final String CLASS = "class";
        private static final String ATTACK = "attack";
        private static final String DEFENCE = "defence";
        private static final String CAVALRY_DEFENCE = "cavalry_defence";
        private static final String SPEED = "speed";
        private static final String CARRYING_CAPACITY = "carrying_capacity";

        public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {

            UnitType type = new UnitType();
            type.setId((Integer)rs.getObject(ID));
            type.setName(rs.getString(NAME));
            type.setImplementingClassName(rs.getString(CLASS));
            type.setAttack(rs.getInt(ATTACK));
            type.setDefence(rs.getInt(DEFENCE));
            type.setCavalryDefence(rs.getInt(CAVALRY_DEFENCE));
            type.setSpeed(rs.getInt(SPEED));
            type.setCarryingCapacity(rs.getInt(CARRYING_CAPACITY));
            return type;
        }
    }
    
    /* (non-Javadoc)
     * @see travibot.meta.dao.UnitTypeDAO#deleteStructureType(travibot.meta.UnitType)
     */
    public void deleteUnitType(UnitType type) {

        // TODO Auto-generated method stub

    }

    /* (non-Javadoc)
     * @see travibot.meta.dao.UnitTypeDAO#getStructureType(java.lang.String)
     */
    public UnitType getUnitType(String name) throws DescriptionNotFoundException {

        UnitType result;
        RowMapper mapper = new BuildingTypeRowMapper();
        try {
            String locale = localeSelector.getLocale().toString();
            StringBuffer sb = new StringBuffer();
            sb.append("select type.id_type, TEXT.text, type.class from ");
            sb.append("UNIT_NAME as unit ");
            sb.append(" inner join " + TABLE_TYPE + " as type ON unit.ID_TYPE = type.ID_TYPE ");
            sb.append(" inner join LOCALE ON unit.ID_LOCALE = LOCALE.ID_LOCALE ");
            sb.append(" inner join TEXT ON unit.ID_TEXT = TEXT.ID_TEXT ");
            sb.append("where (LOCALE.ID_LOCALE = ? and TEXT.text = ?)");
            result = (UnitType)jdbcTemplate.queryForObject(sb.toString(), new Object[] { locale, name }, mapper);
        }
        catch (EmptyResultDataAccessException e) {
            throw new DescriptionNotFoundException(e);
        }
        return result;
    }

    /* (non-Javadoc)
     * @see travibot.meta.dao.UnitTypeDAO#insertStructureType(travibot.meta.UnitType)
     */
    public void insertUnitType(UnitType type) {       
        
        String sql = "insert into " + TABLE_TYPE + " (class, attack, defence, cavalry_defence, speed, carrying_capacity) values (?,?,?,?,?,?)";
        jdbcTemplate.update(sql, new Object[] { type.getImplementingClassName(), type.getAttack(), type.getDefence(), 
                                                type.getCavalryDefence(), type.getSpeed(), type.getCarryingCapacity() });
        sql = "select max(id_type) from " + TABLE_TYPE;
        type.setId(jdbcTemplate.queryForInt(sql));

        sql = "insert into " + TABLE_TEXT + " (text) values (?)";
        jdbcTemplate.update(sql, new Object[] { type.getName() });
        sql = "select max(id_text) from " + TABLE_TEXT;
        int idText = jdbcTemplate.queryForInt(sql);

        sql = "insert into " + TABLE_NAME + " (ID_TEXT, ID_LOCALE, ID_TYPE) values (?, ?, ?)";
        jdbcTemplate.update(sql, new Object[] { idText, localeSelector.getLocale().toString(), type.getId() });
        
        //sesnam materialu
        for(Material currentMaterial : materialFactory.getMaterials()){
            try{
                // vezmu jeho cost
                int materialCost = type.getCost().getCost(currentMaterial);
        
                //ulozim cost a material ID - neprojde, nemam cas, koukni na to. diky
                sql = "insert into " + TABLE_COST + " (ID_MATERIAL, material_count) values (?,?)";
                jdbcTemplate.update(sql, new Object[] { currentMaterial.getId(), materialCost });
                sql = "select max(id_cost) from " + TABLE_COST;
                int idCost = jdbcTemplate.queryForInt(sql);
            
                //ulozim zaznam do vazebni tabulky
                sql = "insert into " + TABLE_UNIT_COSTS + " (ID_COST, ID_UNIT_TYPE) values (?,?)";
                jdbcTemplate.update(sql, new Object[]{ idCost, type.getId()});
            }
            catch(NullPointerException ex){                
                
                continue; // pokud nebyl zadany material v type.getCost.getCost(Material), tak jedu dal pro dalsi materialy
            }
        }
    }

    
    public void setMaterialFactory(MaterialFactory materialFactory) {
    
        this.materialFactory = materialFactory;
    }
}
